import anime from 'animejs'
import { edgeConfig } from '../config/edgeConfig'
import { sizeConfig } from '../config/sizeConfig'
import { BoolType, IModuleWithState } from '../types'
import {
    createDataValue,
    getCenterPoint,
    setDomBoolVal,
    setDomDataItemVal,
    toBinaryStr,
    $,
    toInt255,
} from '../utils'
import { bus3, bus4 } from './bus'
import { multiplexer21 } from './mutiplexer21'

interface IRegState {
    sr1: BoolType
    sr0: BoolType
    dr1: BoolType
    dr0: BoolType
    we: BoolType
    r0: number
    r1: number
    r2: number
    r3: number
}

interface IReg extends IModuleWithState<IRegState> {
    setDataAnimation: () => Promise<void>
}

/**
 * 处理编辑reg逻辑
 */
function initEditReg() {
    // 给reg的dom注册点击事件
    $('.reg .content-2')?.addEventListener('click', () => {
        // 显示模态框
        $('.reg-edit')?.classList.remove('hide')
        const regs = ['r0', 'r1', 'r2', 'r3'] as const
        // 初始化模态框内的文本域的内容
        regs.forEach((item) => {
            const input = $(`.reg-edit .input-${item}`) as any
            input.value = toBinaryStr(reg.state[item], 8, true)
        })
    })

    // 关闭按钮
    $('.reg-edit .close')?.addEventListener('click', () => {
        $('.reg-edit')?.classList.add('hide')
        const regs = ['r0', 'r1', 'r2', 'r3'] as const
        // 清空
        regs.forEach((item) => {
            const input = $(`.reg-edit .input-${item}`) as any
            input.value = ''
        })
    })

    // 保存按钮
    $('.reg-edit .save')?.addEventListener('click', () => {
        const regs = ['r0', 'r1', 'r2', 'r3'] as const
        regs.forEach((item) => {
            const input = $(`.reg-edit .input-${item}`) as any
            const inputVal = input.value
            const intValue = toInt255(inputVal)
            if (reg.state[item] !== intValue) {
                reg.setState(item, intValue)
            }
            input.value = ''
        })
        $('.reg-edit')?.classList.add('hide')
    })
}

/**
 * reg模块
 */
export const reg: IReg = {
    name: 'reg',
    state: {
        sr1: 0,
        sr0: 0,
        dr1: 0,
        dr0: 0,
        we: 0,
        r0: RegInitialData.r0,
        r1: RegInitialData.r1,
        r2: RegInitialData.r2,
        r3: RegInitialData.r3,
    },
    async setState(prop, value) {
        if (this.state[prop] === value) return
        this.state[prop] = value
        if (['sr1', 'sr0', 'dr1', 'dr0', 'we'].includes(prop)) {
            setDomBoolVal(prop, this.state[prop] as BoolType)
        } else if (['r0', 'r1', 'r2', 'r3'].includes(prop)) {
            setDomDataItemVal(
                `.reg .content .data-item-val.${prop}`,
                this.state[prop]
            )
        }
        if (prop != 'we') {
            this.setDataAnimation()
        }
        return
    },
    async setDataAnimation() {
        const regTopCenter = getCenterPoint(sizeConfig.reg, 'top')
        const regBottomCenter = getCenterPoint(sizeConfig.reg, 'bottom')
        // 根据sr0，sr1的值，从r0-r3中选择一个寄存器，将其值送到S口
        // @ts-ignore
        // 当前sr1sr0的值
        const sr: 0 | 1 | 2 | 3 = (this.state.sr1 << 1) | this.state.sr0
        // sr1sr0的值对应的寄存器的值
        const srData = this.state[`r${sr}`]
        // sr1sr0的值对应的寄存器的中心点
        const rCenter = {
            x: regBottomCenter.x,
            y: regBottomCenter.y - (4 - sr) * 10 - 15,
        }
        // S口的中心点
        const sCenter = {
            x: regTopCenter.x - sizeConfig.reg.width / 4,
            y: regTopCenter.y,
        }
        // 要做动画的数据
        const sData = createDataValue(srData, toBinaryStr(srData), rCenter)
        const timeline1 = anime.timeline({
            targets: sData.dom,
            duration: (edgeConfig.time.neg + edgeConfig.time.low) * 0.15,
            easing: 'linear',
        })
        timeline1.add({
            translateX: sCenter.x,
            translateY: sCenter.y - 10,
            complete: () => {
                bus3.setData(srData)
                sData.dom.remove()
            },
        })
        // 根据dr0，dr1的值，从r0-r3中选择一个寄存器，将其值送到D口
        // @ts-ignore
        // 当前dr1dr0的值
        const dr: 0 | 1 | 2 | 3 = (this.state.dr1 << 1) | this.state.dr0
        // dr1dr0的值对应的寄存器的值
        const drData = this.state[`r${dr}`]
        // dr1dr0的值对应的寄存器的中心点
        const dRCenter = {
            x: regBottomCenter.x,
            y: regBottomCenter.y - (4 - dr) * 10 - 15,
        }
        // D口的中心点
        const dCenter = {
            x: regTopCenter.x + sizeConfig.reg.width / 4,
            y: regTopCenter.y,
        }
        // 要做动画的数据
        const dData = createDataValue(drData, toBinaryStr(drData), dRCenter)
        const timeline2 = anime.timeline({
            targets: dData.dom,
            duration: (edgeConfig.time.neg + edgeConfig.time.low) * 0.15,
            easing: 'linear',
        })
        timeline2.add({
            translateX: dCenter.x,
            translateY: dCenter.y - 10,
            complete: () => {
                bus4.setData(drData)
                dData.dom.remove()
            },
        })
    },
    async neg() {
        // 在时钟下降沿触发时
        if (this.state.we === 1) {
            // 根据dr0，dr1的值，从21选择器中拿数据，放到寄存器r0-r3中
            const regBottomCenter = getCenterPoint(sizeConfig.reg, 'bottom')
            // @ts-ignore
            // 当前dr1dr0的值
            const dr: 0 | 1 | 2 | 3 = (this.state.dr1 << 1) | this.state.dr0
            // dr1dr0的值对应的寄存器的值
            const m21Data = multiplexer21.state.value
            // dr1dr0的值对应的寄存器的中心点
            const dRCenter = {
                x: regBottomCenter.x,
                y: regBottomCenter.y - (4 - dr) * 10 - 15,
            }
            // 要做动画的数据
            const dData = createDataValue(
                m21Data,
                toBinaryStr(m21Data),
                regBottomCenter
            )
            const timeline1 = anime.timeline({
                targets: dData.dom,
                duration: (edgeConfig.time.neg + edgeConfig.time.low) * 0.15,
                easing: 'linear',
            })
            return timeline1.add({
                translateX: dRCenter.x,
                translateY: dRCenter.y - 10,
                complete: () => {
                    this.setState(`r${dr}`, m21Data)
                    dData.dom.remove()
                },
            }).finished
        }
    },
    init() {
        ;['sr1', 'sr0', 'dr1', 'dr0', 'we'].forEach((prop) => {
            // @ts-ignore
            setDomBoolVal(prop, this.state[prop] as BoolType)
        })
        ;['r0', 'r1', 'r2', 'r3'].forEach((prop) => {
            setDomDataItemVal(
                `.reg .content .data-item-val.${prop}`,
                // @ts-ignore
                this.state[prop]
            )
        })
        this.setDataAnimation()

        // 编辑reg
        initEditReg()
    },
}
